home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / Libraries / VideoToolbox 97.08.16 / VideoToolboxSources / CopyBitsQuickly.c < prev    next >
Encoding:
Text File  |  1997-07-09  |  30.7 KB  |  784 lines  |  [TEXT/CWIE]

  1. /*
  2. CopyBitsQuickly.c
  3.  
  4. NOTE: CopyBitsQuickly.c, for highest possible speed, now uses Apple's
  5. BlockMoveDataUncached() on PCI Macs, and BlockMoveData() otherwise. As a
  6. consequence, all PowerPC projects that include CopyBitsQuickly.c must add
  7. DriverServicesLib (it's from Apple, and included on the Metrowerks CodeWarrior CD-ROM),
  8. which has the glue
  9. needed to call BlockMoveDataUncached(). If you're using CodeWarrior, after adding
  10. DriverServicesLib to your project, press the little arrow next to
  11. DriverServicesLib and select "import 'weak'" from the pop-up menu. When you Make,
  12. ignore the Link Warning that BlockMove and BlockMoveData were previously defined
  13. in InterfaceLib. E.g. see the demo TimeVideo.
  14.  
  15. CopyBitsQuickly.c is a dumb substitute for CopyBits that ignores the color
  16. tables and palettes, simply copying the raw pixels without any translation. It's
  17. for doing animations. (Try the demo Sandstorm.) Besides copying images, it can
  18. also add or multiply them. At one time it copied much faster than CopyBits did,
  19. but the latest timing (under System 7), by TimeVideo, indicates that they are of
  20. approximately equal speed.
  21.  
  22. Apple's CopyBits is an Apple Macintosh Toolbox routine for copying images, and
  23. is documented in Inside Macintosh Volumes I,V, and VI, and New Inside Macintosh:
  24. "Imaging with QuickDraw". CopyBitsQuickly does not cause the Memory Manager to
  25. move memory, and thus may be used in a VBL task.
  26.  
  27. I suggest that you use the higher-level interface provided by
  28. the VideoToolbox CopyWindows.c, which saves you from getting your hands dirty
  29. messing with pixmaps. You can just deal with windows and GWorlds.
  30.  
  31. The returned value is nonzero if an error occurred.
  32.  
  33. CopyBitsQuickly supports four modes:
  34. • srcCopy copies the source to the destination.
  35. • addOver adds the source to the destination. Both must have 8-bit pixels.
  36. Overflow is ignored.
  37. • addOverParallel adds the source to the destination (4 bytes at a time), i.e.
  38. parallel addition. Overflow may carry over into neighboring pixels within the image.
  39. Supports all pixel sizes.
  40. • mulOver causes the source and destination to be multiplied, pixel by pixel. Both
  41. must have 8-bit pixels. After multiplication, the product is divided by 128 and
  42. stored in the destination. Overflow is ignored. All the arithmetic is unsigned.
  43.  
  44. RESTRICTIONS:
  45. • srcBits and dstBits must both have the same number of bits/pixel.
  46. • dstRect and srcRect must have the same size.
  47. • mode must be either srcCopy, addOver, addOverParallel, or mulOver.
  48. • maskRgn must be NULL.
  49. • If mode is addOver or mulOver then the pixel size must be 8 bits.
  50. • If CopyBitsQuickly detects a violation of any of these restrictions it will return
  51. a nonzero value, indicating that an error occured.
  52.  
  53. RETURNED VALUE:
  54. 0 Success.
  55. 1 Illegal srcMode (only srcCopy, addOver, and mulOver are allowed). 
  56. 2 maskRgn!=NULL.
  57. 3 Source and destination rects are of unequal size.
  58. 4 After clipping there were no pixels to copy, or RectToAddress couldn't resolve 
  59.     address of source or destination.
  60. 5 Source and destination have unequal pixel sizes.
  61. 6 We need 32-bit addressing but it's not available.
  62. 7 This mode requires 8-bit pixels and the supplied pixel size is not 8 bits.
  63.  
  64. ACKNOWLEDGEMENTS:
  65. I learned the trick of using a switch() to jump into a loop from Bill Karsh's solution
  66. to the April 1994 MacTech Programmer's Challenge.
  67.  
  68. LIMITATIONS:
  69. • If a Rect extends across multiple screens, only as much of the upper-left of
  70. the Rect that's on one device will be used. The rest is clipped off.
  71. • When accessing a screen, CopyBitsQuickly() ought to, but doesn't, call
  72. ShieldCursor() to remove the cursor from the part of the screen it's reading or
  73. writing. Calling ShieldCursor would also have the desirable side effect of
  74. informing nonstandard video devices, like the Radius PowerView, that the screen
  75. has been updated. (NOTE: CopyWindows does this for you before calling CopyBitsQuickly.)
  76.  
  77. NOTE: For highest speed you should choose your srcRectPtr & dstRectPtr so that
  78. the first point moved to and from each row begins at a memory address that is a
  79. multiple of 4 bytes. The effect on speed is substantial, about 25%.
  80.  
  81. NOTE: If your computer boots in 24-bit mode, as set by the Memory Control Panel,
  82. then the THINK C Debugger will crash if it's activated while you've temporarily
  83. switched into 32-bit mode. So don't put any breakpoints in any section of code
  84. that's bracketed by calls to SwapMMUMode() unless your computer booted up in
  85. 32-bit mode. If your computer boots in 32-bit mode then the calls to SwapMMUMode
  86. do nothing, and you can put Debugger breakpoints anywhere.
  87.  
  88. BlockMoveData & BlockMoveDataUncached
  89.  
  90. For highest possible speed, CopyBitsQuickly.c, if possible, now uses Apple's 
  91. BlockMoveDataUncached() on PCI PowerPC Macs and otherwise uses BlockMoveData(). 
  92. For discussion
  93. see <http://rajsky.psych.nyu.edu/VideoToolbox/videonotes/fastblittingtip.html>.
  94.  
  95. BlockMoveDataUncached is new, available only on the PCI Power Macs. You can't use
  96. BlockMoveData on PowerPC macs to copy to video, because video is uncached and
  97. one of the instructions used by BlockMoveData runs extremely slowly when
  98. writing to uncached memory. BlockMoveDataUncached is designed specifically for
  99. writing to uncached memory. In my timing it seems to be about 10% faster than
  100. my loop and CopyBits on my 7500/100.
  101.  
  102. BlockMoveData is a variant of BlockMove that omits cache flushing. 
  103. It arrived in System Update 3.0 to System 7. Issuing BlockMoveData() on earlier versions
  104. of the operating system will invoke plain-old BlockMove(). BlockMoveData, like
  105. BlockMove, uses the MOVE16 instruction, on computers that have it, so it could
  106. potentially be faster than the generic code that most compilers produce.
  107. However, I didn't found any speed advantage on the PowerBook 170, Mac II, IIfx,
  108. and Power Mac in my lab (none of which have the 68040, which is the only cpu
  109. that has MOVE16). I haven't tried it on a Quadra. 
  110.  
  111. The use of BlockMoveData is disabled if the computer has a 68040
  112. processor, yet is a Mac II. I do this because BlockMoveData crashed on my Radius
  113. Rocket (68040 processor on a NuBus card) in my Mac II when handed addresses in
  114. video memory, even though MODE32 was installed. Presumably this indicates that
  115. the BlockMove routine was not 32-bit clean, despite the runtime patches installed
  116. by MODE32. This is puzzling since BlockMove works fine accessing the same video
  117. addresses in either 24 or 32-bit mode (with MODE32) without the Rocket.
  118.  
  119. Copyright ©1989-1997 Denis G. Pelli.
  120.  
  121. Received:    1/28/96 12:46 PM
  122.  
  123. "When is it safe to call BlockMoveDataUncached?"
  124.  
  125. This function is part of the PCI Driver Services Library and as such should not
  126. be called from an application. To determine if the machine upon which your
  127. application is running, is PCI do the following.
  128.  
  129. You must first check if the NameRegistry exists. There is a Gestalt Manager
  130. selector for
  131. this, 'nreg'. If it exists, the value returned will be the version number (
  132. number 1 for now) of the Name Registry. Otherwise, you should get a
  133. gestaltUndefSelectorErr. If the Name Registry does not exist then you should
  134. assume that it is not a PCI based machine. At this point it can be NuBus or no
  135. bus at all.
  136.  
  137. You can use the Name Registry to determine if a PCI bus exists. To do this you
  138. should use RegistryEntrySearch to locate an entry/node having a known
  139. property/value, propertyName = "devic-type", and propertyValue = "pci"  If an
  140. entry is found that has that known property/value (noErr and done = "False"),
  141. there is a PCI bus.
  142.  
  143. You do not need to worry about cache topology if you're a driver writer. The
  144. newer MacOS(tm) removes this burden from the writer by supplying BlockCopy. This
  145. function will always know the cache topology and forward your request to the
  146. appropriate copy routine.
  147.  
  148. Regards
  149.  
  150. Wayne Flansburg
  151. DTS
  152. Apple Computer
  153.  
  154. 3/19/96 dgp as advised by Wayne at apple, above, i tried replacing my call to BlockMoveData by
  155. BlockCopy, but BlockCopy runs ten time SLOWER (under System 7.5.3 on a 7500/100), 
  156. which defeats the purpose. Wayne notes that we can only use these routines
  157. on PCI Macs. Apparently when Copland comes they will be available solely to
  158. device drivers, which suggests that CopyBitsQuickly.c may then need to be implemented
  159. partly as a device driver.
  160.  
  161. >From elliott@mpi-muelheim.mpg.de (Mark Elliott)
  162. Subject: Direct-to-screen drawing and Copland
  163. Date: Thu, 14 Mar 1996 15:37:43 +0100
  164. Organization: Max-Planck-Institut f. Kohlenforsch. Muelheim
  165.  
  166. Hi All,
  167.  
  168. There has been a bit of debate about this, and I just got my latest
  169. developer mailing today, and here's the verdict.
  170.  
  171. (not an exact quote, but the content of the quote is specific)
  172.  
  173. 'Apple realises that some applications (specifically games are mentioned)
  174. NEED (my emphasis) direct-to-screen drawing. As long as you follow the
  175. guidelines set forth in the Develop article by Brigham Stevens (issue 11
  176. ?) then applications using this technique will still work under Copland
  177. (assuming you don't break any other rules, of course!)'.
  178.  
  179. What this means is locking PixMaps. Getting base address using
  180. GetPixBaseAddr(), etc.
  181.  
  182. I have not interpreted the text. It is all there in black and white. So
  183. one possible cause for game-programmers to worry about Copland is sorted.
  184.  
  185. hope this reassures you.
  186.  
  187. Mark
  188.  
  189. - ------------------------------------------------------------------
  190. Mark C Elliott                           elliott@mpi-muelheim.mpg.de
  191. Max-Planck-Institut                      voice: (+49) 208 306 2429
  192. Fuer Kohlenforschung
  193. Muelheim, Germany
  194. - ------------------------------------------------------------------
  195.  
  196. REFERENCE:
  197. TechNote 1083 Weak-linking to a Code Fragment Manager-based shared library
  198. http://devworld.apple.com/dev/technotes/tn/tn1083.html
  199.  
  200. HISTORY:
  201. 1/89 dgp    Version 2.0: added support for PixMaps and multiple screens. Added checking.
  202. 6/89 dgp    Version 3.0: now use RectToAddress, which clips to one device.
  203. 10/89 dgp    Version 3.5: Improved resolution from longs to bytes.
  204. 10/89 dgp    Version 4.0: Added new mode: addOver
  205. 3/90  dgp    Version 4.01: Made cosmetic changes:
  206.             renamed srcRect & dstRect to srcRectPtr and dstRectPtr.
  207.             renamed srcAdd to addOver, to conform to CopyBits.
  208.             added a few more comments to explain the initial clipping.
  209. 3/20/90    dgp    made compatible with MPW C.
  210. 4/20/90    dgp    now uses 32-bit addressing only if QD32 is present.
  211. 4/9/91    dgp    v 4.05: changed nudge from short to long, just to be safe
  212. 8/24/91    dgp    Made compatible with THINK C 5.0.
  213. 4/15/92    dgp    Updated CopyBitsQuickly's function header to Standard C style.
  214. 10/5/92 dgp    Dropped support for THINK C 4. Updated the documentation above.
  215. 12/2/92 dgp cosmetic changes
  216. 12/8/92 dgp fixed major gaffe introduced on 12/2/92: "case" prefix was 
  217.             missing in switch statement. This caused CopyBitsQuickly to do nothing. 
  218. 1/31/93    dgp    Added new "multiplyQuickly" mode requested by Josh Solomon. Now 
  219.             insist on 8-bit pixels for both addOver and multiplyQuickly modes.
  220. 2/18/93    js    added mulOver to list of allowed modes. (Oops! - dgp.) Works ok now.
  221. 2/18/93    dgp    Now return int, nonzero if error occurred.
  222. 7/9/93    dgp check for 32-bit addressing capability.
  223. 6/5/94    dgp Replaced all assembly code by portable C code of similar speed. Only call 
  224.             SwapMMUMode() if we must. Give error if we need 32-bit mode and it's not 
  225.             available. Documented the returned value.
  226. 6/7/94    dgp    Added code to use Apple's BlockMoveData() for highest
  227.             possible speed on all Macs, but disabled it because it didn't turn
  228.             out to be faster on the machines on which I've tested it: Mac II, IIfx,
  229.             and Power Mac 6100/60.
  230. 6/7/94    dgp    Added new mode "addOverParallel" which accepts any pixelSize and adds
  231.             source to destination very quickly by adding 4 bytes at a time.
  232. 6/14/94    dgp    can32 is now computed by calling TrapAvailable(_SwapMMUMode), which 
  233.             returns the correct answer even on Macs with dirty ROMs.
  234. 5/23/95 dgp Apple changed the prototype in the header file from SwapMMUMode(char *) to 
  235.             SwapMMUMode(signed char *). To retain compatibility with both old and new
  236.             headers, I cast the argument (void *).
  237. 1/25/96 dgp Enabled use of BlockMoveData and BlockMoveDataUncached.
  238. 1/28/96 dgp only call BlockMoveDataUncached on PCI Macs; otherwise use BlockMoveData.
  239. 3/4/96 dgp made compatible with THINK C 7.
  240. 7/9/96 dgp explained the need for DriverServicesLib, as suggested by Preeti Verghese.
  241. 4/10/97    dgp    Eliminate stuff that was conditional on !UNIVERSAL_HEADERS.
  242. 5/19/97 dgp Added URLs to documents now in website VideoNotes folder.
  243. 7/9/97    dgp    Simplified the test for availability of BlockMoveDataUncached, based on TN1083.
  244.             Eliminated the confusing redefinition of BlockMoveDataUncached, and instead
  245.             enclosed all instances in #ifs.
  246. */
  247. #include "VideoToolbox.h"
  248. void ReadPixels(int x,int y,int n,unsigned long *value
  249.     ,unsigned char *baseAddr,long pixelSize,long rowBytes);
  250. void WritePixels(int x,int y,int n,unsigned long *value
  251.     ,unsigned char *baseAddr,long pixelSize,long rowBytes);
  252. extern void BlockMoveUncached(const void *srcPtr, void *destPtr, Size byteCount);
  253. #if GENERATINGPOWERPC
  254. // BlockMoveDataUncached is only available on PCI PowerMacs. 
  255. // Apparently video buffers are "uncacheable" and BlockMoveData uses an instruction 
  256. // that is emulated slowly in that case.
  257.     extern void BlockMoveDataUncached(const void *srcPtr, void *destPtr, Size byteCount);
  258.     extern void BlockCopy(const void *srcPtr, void *destPtr, Size byteCount);
  259. #endif
  260. // The srcMode constants addOverParallel and mulOver are defined in VideoToolbox.h
  261. #ifndef __TRAPS__
  262.     #include <Traps.h>        // _SwapMMUMode
  263. #endif
  264. #if (THINK_C || THINK_CPLUS || SYMANTEC_C)
  265.     // These THINK C options seem to have very little effect on the code produced.
  266.     // However, if you don't disable "assign_registers" then one of the variables
  267.     // declared "register" in srcCopyQuickly() fails to be assigned to a register.
  268.     #pragma options(!assign_registers,honor_register,redundant_loads,defer_adjust)
  269.     #pragma options(global_optimizer,gopt_induction,gopt_loop,gopt_cse,gopt_coloring)
  270. #endif
  271. #ifndef __CODEFRAGMENTS__
  272.     #include <CodeFragments.h>
  273. #endif
  274.  
  275. typedef unsigned char *UPtr;
  276.  
  277. static void Expand8(double hMag,double vMag,double hOffset,double vOffset
  278.     ,register UPtr Src,Rect *srcRect,unsigned long srcRowBytes
  279.     ,register UPtr Dst,Rect *dstRect,unsigned long dstRowBytes,Boolean do32);
  280. static void Expand(double hMag,double vMag,double hOffset,double vOffset
  281.     ,register UPtr Src,Rect *srcRect,int srcPixelBits,unsigned long srcRowBytes
  282.     ,register UPtr Dst,Rect *dstRect,int dstPixelBits,unsigned long dstRowBytes,Boolean do32);
  283. static void SrcCopyQuickly(UPtr Src,unsigned long srcinc,
  284.     UPtr Dst,unsigned long dstinc,
  285.     unsigned long bytes,unsigned long lines,Boolean do32);
  286. static void SrcCopyQuickly2(UPtr Src,unsigned long srcinc,
  287.     UPtr Dst,unsigned long dstinc,
  288.     unsigned long bytes,unsigned long lines,Boolean do32);
  289. static void AddOverParallel(UPtr Src,unsigned long srcinc,
  290.     UPtr Dst,unsigned long dstinc,
  291.     unsigned long bytes,unsigned long lines,Boolean do32);
  292. static void AddOver8(UPtr Src,unsigned long srcinc,
  293.     UPtr Dst,unsigned long dstinc,
  294.     unsigned long bytes,unsigned long lines,Boolean do32);
  295. static void MulOver8(UPtr Src,unsigned long srcinc,
  296.     UPtr Dst,unsigned long dstinc,
  297.     unsigned long bytes,unsigned long lines,Boolean do32);
  298.  
  299. static Boolean haveBlockMoveDataUncached;    // Only the PCI PowerMacs have BlockMoveDataUncached.
  300.  
  301. int CopyBitsQuickly(BitMap *srcBits,BitMap *dstBits
  302.     ,Rect *srcRectPtr,Rect *dstRectPtr,long srcMode,RgnHandle maskRgn)
  303. {
  304.     UPtr Src,Dst;
  305.     long srcinc,dstinc;
  306.     unsigned long lines;
  307.     short srcRowBytes,dstRowBytes,srcPixelSize,dstPixelSize,srcBitsOffset,dstBitsOffset;
  308.     Rect mySrcRect,myDstRect;
  309.     int hOffset,vOffset;
  310.     double hMag,vMag;
  311.     long nudge,bytes;
  312.     Boolean do32,useBlockMove;
  313.     static Boolean can32,is32,wantBlockMove,firstTime=1;
  314.     long error,addressing,machine,processor;
  315.  
  316.     srcMode&=0xffff;    // upper bits are used only by CopyWindows.
  317.     if(srcMode != srcCopy && srcMode != addOver && srcMode != addOverParallel && srcMode != mulOver)
  318.         return 1;
  319.     if(maskRgn != NULL) return 2;
  320.  
  321.     /* clip the rect to be copied by the bounds of source and destination */
  322.     mySrcRect=*srcRectPtr;
  323.     myDstRect=*dstRectPtr;
  324.  
  325.     hMag=(double)(myDstRect.right-myDstRect.left)/(mySrcRect.right-mySrcRect.left);
  326.     vMag=(double)(myDstRect.bottom-myDstRect.top)/(mySrcRect.bottom-mySrcRect.top);
  327.     if((vMag!=1 || hMag!=1) && srcMode!=srcCopy)return 3;
  328.     /* first make sure that srcRect and dstRect are the same size */
  329. //    if(mySrcRect.bottom-mySrcRect.top != myDstRect.bottom-myDstRect.top || 
  330. //        mySrcRect.right-mySrcRect.left != myDstRect.right-myDstRect.left) 
  331. //            return 3;
  332.  
  333.     hOffset=myDstRect.left-mySrcRect.left*hMag;
  334.     vOffset=myDstRect.top-mySrcRect.top*vMag;
  335.     /* clip myDstRect */
  336.     Dst = RectToAddress((PixMap *)dstBits,&myDstRect,&dstRowBytes,&dstPixelSize,&dstBitsOffset);
  337.  
  338.     /*
  339.     This prevents writing outside the destination.
  340.     The cost is that part of the inside will not be written.
  341.     The problem arises because this routine's code can only write whole bytes,
  342.     and the boundary may be in the middle of a byte. So, rather than writing an
  343.     extra fraction of a byte (outside the destination rect) we leave the byte
  344.     alone and fail to update a small portion inside the destination rect.
  345.     */
  346.     if(dstBitsOffset>0) {
  347.         nudge=(7+dstBitsOffset)/8;
  348.         dstBitsOffset -= nudge*8;
  349.         Dst += nudge;
  350.         myDstRect.left += nudge*8/dstPixelSize;
  351.     }
  352.  
  353.     /* Copy any clipping of myDstRect over to mySrcRect */
  354.     mySrcRect=myDstRect;
  355.     ExpandAndOffsetRect(&mySrcRect,1/hMag,1/vMag,-hOffset/hMag,-vOffset/vMag);
  356.     /* clip mySrcRect */
  357.     Src=RectToAddress((PixMap *)srcBits,&mySrcRect
  358.         ,&srcRowBytes,&srcPixelSize,&srcBitsOffset);
  359.  
  360.     /* Copy any clipping of mySrcRect back to myDstRect */
  361.     myDstRect=mySrcRect;
  362.     ExpandAndOffsetRect(&myDstRect,hMag,vMag,hOffset,vOffset);
  363.     Dst=RectToAddress((PixMap *)dstBits,&myDstRect
  364.         ,&dstRowBytes,&dstPixelSize,&dstBitsOffset);
  365.  
  366.     if(Src==NULL || Dst==NULL) return 4;
  367.     if(srcPixelSize != dstPixelSize && srcMode!=srcCopy) return 5;
  368.     bytes = mySrcRect.right - mySrcRect.left;    /* number of pixels per line */
  369.     bytes *= srcPixelSize;                        /* number of bits per line */
  370.     bytes /= 8;                                    /* number of bytes per line */
  371.     srcinc = srcRowBytes - bytes;                /* offset in bytes to beginning of next line */
  372.     dstinc = dstRowBytes - bytes;
  373.     lines=mySrcRect.bottom - mySrcRect.top;        /* number of lines */
  374.     if(srcinc==0 && dstinc==0){
  375.         bytes*=lines;
  376.         lines=1;
  377.     }
  378.     if(firstTime){
  379.         can32=TrapAvailable(_SwapMMUMode);
  380.         addressing=0;
  381.         error=Gestalt(gestaltAddressingModeAttr,&addressing);
  382.         is32=addressing&(1L<<gestalt32BitAddressing);
  383.         #if GENERATINGCFM && GENERATINGPOWERPC
  384.             // BlockMoveDataUncached is fast, but needs the glue in DriverServicesLib.
  385.             haveBlockMoveDataUncached= (Ptr)BlockMoveDataUncached != (Ptr)kUnresolvedCFragSymbolAddress;
  386.         #else
  387.             haveBlockMoveDataUncached=0;
  388.         #endif
  389.         wantBlockMove=1;
  390.         if(GENERATINGPOWERPC)wantBlockMove=wantBlockMove && haveBlockMoveDataUncached;
  391.         /*
  392.         #if GENERATINGCFM
  393.             if(wantBlockMove){
  394.                 // The BlockMoveDataUncached glue is in a shared library.
  395.                 // If the DriverServicesLib is weak-linked, and missing, we need to
  396.                 // check for the library, to prevent a crash if we try to access the 
  397.                 // library's exports.
  398.                 CFragConnectionID        connID;
  399.                 Ptr                        mainAddr;
  400.                 Str255                    errName;
  401.                 long templong;
  402.                 
  403.                 error=Gestalt(gestaltCFMAttr,&templong);    // Code Fragment Manager?
  404.                 if(!error)error=GetSharedLibrary((ConstStr63Param)"\pDriverServicesLib"
  405.                     ,kAnyCFragArch,kFindCFrag,&connID,&mainAddr,errName);
  406.                 if(error)wantBlockMove=0;    // No DriverServicesLib
  407.     //            if(error)printf("\nGetSharedLibrary error=%d, %#s\n\007",(int)error, errName);
  408.             }
  409.         #endif
  410.         */
  411.         if(wantBlockMove){
  412.             // Crude test for Rocket accelerator in Mac II.
  413.             // BlockMove to or from a video address crashed my Radius Rocket.
  414.             error=Gestalt(gestaltProcessorType,&processor);
  415.             error=Gestalt(gestaltMachineType,&machine);
  416.             if(machine==gestaltMacII && processor==gestalt68040)wantBlockMove=0;
  417.         }
  418.         firstTime=0;
  419.     }
  420.     // Must we switch to 32-bit addressing?
  421.     do32=(unsigned long)Src>0xffffffUL || (unsigned long)Dst>0xffffffUL;
  422.     do32=do32 && !is32;
  423.     if(do32 && !can32)return 6;
  424.     // Can't use traps if we switch 24/32-bit mode.
  425.     useBlockMove=wantBlockMove && !do32 && srcPixelSize==dstPixelSize;
  426.  
  427.     switch(srcMode){
  428.     case srcCopy:
  429.         if(hMag!=1 || vMag!=1 || srcPixelSize != dstPixelSize){
  430.             if(srcPixelSize==8 && dstPixelSize==8)Expand8(hMag,vMag,hOffset,vOffset
  431.                 ,Src,&mySrcRect,srcRowBytes,Dst,&myDstRect,dstRowBytes,do32);
  432.             else Expand(hMag,vMag,hOffset,vOffset
  433.                 ,Src,&mySrcRect,srcPixelSize,srcRowBytes
  434.                 ,Dst,&myDstRect,dstPixelSize,dstRowBytes,do32);
  435.         } else if(useBlockMove)SrcCopyQuickly2(Src,srcinc,Dst,dstinc,bytes,lines,do32);
  436.         else SrcCopyQuickly(Src,srcinc,Dst,dstinc,bytes,lines,do32);
  437.         break;
  438.     case addOverParallel:
  439.         if(srcPixelSize!=dstPixelSize)return 5;
  440.         AddOverParallel(Src,srcinc,Dst,dstinc,bytes,lines,do32);
  441.         break;
  442.     case addOver:
  443.         if(srcPixelSize!=8 || dstPixelSize!=8)return 7;
  444.         AddOver8(Src,srcinc,Dst,dstinc,bytes,lines,do32);
  445.         break;
  446.     case mulOver:
  447.         if(srcPixelSize!=8 || dstPixelSize!=8)return 7;
  448.         MulOver8(Src,srcinc,Dst,dstinc,bytes,lines,do32);
  449.         break;
  450.     default:
  451.         return 1;
  452.         break;
  453.     }
  454.     return 0;
  455. }
  456.  
  457. static void Expand8(double hMag,double vMag,double hOffset,double vOffset
  458.     ,register UPtr Src,Rect *srcRect,unsigned long srcRowBytes
  459.     ,register UPtr Dst,Rect *dstRect,unsigned long dstRowBytes,Boolean do32)
  460. {
  461.     int hh=round(hMag),vv=round(vMag);
  462.     int srcWidth,dstWidth;
  463.     register int i,j,ii;
  464.     register UPtr src,dst;
  465.     register unsigned char a;
  466.     signed char mmumode=true32b;
  467.  
  468.     hOffset;vOffset;dstRect;    /* unused arguments */
  469.     srcWidth=srcRect->right-srcRect->left;
  470.     dstWidth=srcWidth*hh;
  471.     for(j=srcRect->bottom-srcRect->top;j>0;j--){
  472.         src=Src;
  473.         dst=Dst;
  474.         if(do32)SwapMMUMode((void *)&mmumode);    /* set 32-bit mode */
  475.         for(i=srcWidth;i>0;i--){
  476.             a=*src++;
  477.             for(ii=hh;ii>0;ii--)*dst++=a;
  478.         }
  479.         if(do32)SwapMMUMode((void *)&mmumode);    /* set 32-bit mode */
  480.         src=Dst;
  481.         Dst+=dstRowBytes;
  482.         for(ii=vv-1;ii>0;ii--){
  483.             if(haveBlockMoveDataUncached){
  484.                 #if GENERATINGCFM && GENERATINGPOWERPC
  485.                     BlockMoveDataUncached(src,Dst,dstWidth);
  486.                 #endif
  487.             }else BlockMoveData(src,Dst,dstWidth);
  488.             Dst+=dstRowBytes;
  489.         }
  490.         Src+=srcRowBytes;
  491.     }
  492. }    
  493.  
  494. static void Expand(double hMag,double vMag,double hOffset,double vOffset
  495.     ,register UPtr Src,Rect *srcRect,int srcPixelBits,unsigned long srcRowBytes
  496.     ,register UPtr Dst,Rect *dstRect,int dstPixelBits,unsigned long dstRowBytes,Boolean do32)
  497. {
  498.     int hh=round(hMag),vv=round(vMag);
  499.     long srcWidth,dstWidth,bytes;
  500.     register int i,j,ii;
  501.     register UPtr src;
  502.     signed char mmumode=true32b;
  503.     unsigned long value[1024],v,*srcV,*dstV;
  504.  
  505.     hOffset;vOffset;dstRect;do32;    /* unused arguments */
  506.     srcWidth=srcRect->right-srcRect->left;
  507.     dstWidth=srcWidth*hh;
  508.     bytes=dstWidth*dstPixelBits/8;
  509.     for(j=srcRect->bottom-srcRect->top;j>0;j--){
  510.         ReadPixels(0,0,srcWidth,value,Src,srcPixelBits,srcRowBytes);
  511.         srcV=value+srcWidth-1;
  512.         dstV=value+srcWidth*hh-1;
  513.         for(i=srcWidth;i>0;i--){
  514.             v=*srcV--;
  515.             for(ii=hh;ii>0;ii--)*dstV--=v;
  516.         }
  517.         WritePixels(0,0,dstWidth,value,Dst,dstPixelBits,dstRowBytes);
  518.         src=Dst;
  519.         Dst+=dstRowBytes;
  520.         for(ii=vv-1;ii>0;ii--){
  521.             if(haveBlockMoveDataUncached){
  522.                 #if GENERATINGCFM && GENERATINGPOWERPC
  523.                     BlockMoveDataUncached(src,Dst,bytes);
  524.                 #endif
  525.             }else BlockMoveData(src,Dst,bytes);
  526.             Dst+=dstRowBytes;
  527.         }
  528.         Src+=srcRowBytes;
  529.     }
  530. }    
  531.  
  532. static void SrcCopyQuickly2(register UPtr Src,register unsigned long srcinc,
  533.     register UPtr Dst,register unsigned long dstinc,
  534.     unsigned long bytes,register unsigned long lines,Boolean do32)
  535. {
  536.     // See discussion of BlockMoveData at top of this file.
  537.  
  538.     do32;    /* dgp: prevent "unused argument" warning */
  539.     srcinc+=bytes;
  540.     dstinc+=bytes;
  541.     for(;lines>0;lines--){
  542.         if(haveBlockMoveDataUncached){
  543.             #if GENERATINGCFM && GENERATINGPOWERPC
  544.                 BlockMoveDataUncached(Src,Dst,bytes);
  545.             #endif
  546.         }else BlockMoveData(Src,Dst,bytes);
  547.         Src+=srcinc;
  548.         Dst+=dstinc;
  549.     }
  550. }    
  551.  
  552. #define useMask 0
  553. static void SrcCopyQuickly(UPtr xSrc,register unsigned long srcinc,
  554.     UPtr xDst,register unsigned long dstinc,
  555.     register unsigned long bytes,register unsigned long lines,Boolean do32)
  556. {
  557.     register unsigned long *SrcL=(unsigned long *)xSrc,*DstL=(unsigned long *)xDst;
  558.     register long i;
  559.     signed char mmumode=true32b;
  560.     static unsigned long mask32[4]={0,0xff,0xffff,0xffffff};
  561.     register unsigned long m=mask32[bytes&3];
  562.  
  563.     if(useMask){
  564.         srcinc+=bytes&3;
  565.         dstinc+=bytes&3;
  566.     }
  567.     if(do32)SwapMMUMode((void *)&mmumode);    /* set 32-bit mode */
  568.     for(;lines>0;lines--) {
  569.         i=bytes>>7;
  570.         switch((bytes>>2)&31){
  571.             for(;i>=0;i--){
  572.                             *DstL++ = *SrcL++;
  573.                 case 31:    *DstL++ = *SrcL++;
  574.                 case 30:    *DstL++ = *SrcL++;
  575.                 case 29:    *DstL++ = *SrcL++;
  576.                 case 28:    *DstL++ = *SrcL++;
  577.                 case 27:    *DstL++ = *SrcL++;
  578.                 case 26:    *DstL++ = *SrcL++;
  579.                 case 25:    *DstL++ = *SrcL++;
  580.                 case 24:    *DstL++ = *SrcL++;
  581.                 case 23:    *DstL++ = *SrcL++;
  582.                 case 22:    *DstL++ = *SrcL++;
  583.                 case 21:    *DstL++ = *SrcL++;
  584.                 case 20:    *DstL++ = *SrcL++;
  585.                 case 19:    *DstL++ = *SrcL++;
  586.                 case 18:    *DstL++ = *SrcL++;
  587.                 case 17:    *DstL++ = *SrcL++;
  588.                 case 16:    *DstL++ = *SrcL++;
  589.                 case 15:    *DstL++ = *SrcL++;
  590.                 case 14:    *DstL++ = *SrcL++;
  591.                 case 13:    *DstL++ = *SrcL++;
  592.                 case 12:    *DstL++ = *SrcL++;
  593.                 case 11:    *DstL++ = *SrcL++;
  594.                 case 10:    *DstL++ = *SrcL++;
  595.                 case 9:        *DstL++ = *SrcL++;
  596.                 case 8:        *DstL++ = *SrcL++;
  597.                 case 7:        *DstL++ = *SrcL++;
  598.                 case 6:        *DstL++ = *SrcL++;
  599.                 case 5:        *DstL++ = *SrcL++;
  600.                 case 4:        *DstL++ = *SrcL++;
  601.                 case 3:        *DstL++ = *SrcL++;
  602.                 case 2:        *DstL++ = *SrcL++;
  603.                 case 1:        *DstL++ = *SrcL++;
  604.                 case 0:;
  605.             }
  606.         }
  607.         if(useMask){
  608.             if(m) *DstL=(m & *SrcL) | (!m & *DstL);
  609.         }else{
  610.             if(bytes&2){
  611.                 *(unsigned short *)DstL=*(unsigned short *)SrcL;
  612.                 DstL=(unsigned long *)(1+(unsigned short *)DstL);
  613.                 SrcL=(unsigned long *)(1+(unsigned short *)SrcL);
  614.             }
  615.             if(bytes&1){
  616.                 *(unsigned char *)DstL=*(unsigned char *)SrcL;
  617.                 DstL=(unsigned long *)(1+(unsigned char *)DstL);
  618.                 SrcL=(unsigned long *)(1+(unsigned char *)SrcL);
  619.             }
  620.         }
  621.         DstL=(unsigned long *)(dstinc+(unsigned char *)DstL);
  622.         SrcL=(unsigned long *)(srcinc+(unsigned char *)SrcL);
  623.     }
  624.     if(do32)SwapMMUMode((void *)&mmumode);    /* restore */
  625. }
  626.  
  627. static void AddOverParallel(UPtr xSrc,register unsigned long srcinc,
  628.     UPtr xDst,register unsigned long dstinc,
  629.     register unsigned long bytes,register unsigned long lines,Boolean do32)
  630. {
  631.     register unsigned long *SrcL=(unsigned long *)xSrc,*DstL=(unsigned long *)xDst;
  632.     register long i;
  633.     signed char mmumode;
  634.  
  635.     mmumode=true32b;
  636.     if(do32)SwapMMUMode((void *)&mmumode);    /* set 32-bit mode */
  637.     for(;lines>0;lines--) {
  638.         i=bytes>>7;
  639.         switch((bytes>>2)&31){
  640.             for(;i>=0;i--){
  641.                             *DstL++ += *SrcL++;
  642.                 case 31:    *DstL++ += *SrcL++;
  643.                 case 30:    *DstL++ += *SrcL++;
  644.                 case 29:    *DstL++ += *SrcL++;
  645.                 case 28:    *DstL++ += *SrcL++;
  646.                 case 27:    *DstL++ += *SrcL++;
  647.                 case 26:    *DstL++ += *SrcL++;
  648.                 case 25:    *DstL++ += *SrcL++;
  649.                 case 24:    *DstL++ += *SrcL++;
  650.                 case 23:    *DstL++ += *SrcL++;
  651.                 case 22:    *DstL++ += *SrcL++;
  652.                 case 21:    *DstL++ += *SrcL++;
  653.                 case 20:    *DstL++ += *SrcL++;
  654.                 case 19:    *DstL++ += *SrcL++;
  655.                 case 18:    *DstL++ += *SrcL++;
  656.                 case 17:    *DstL++ += *SrcL++;
  657.                 case 16:    *DstL++ += *SrcL++;
  658.                 case 15:    *DstL++ += *SrcL++;
  659.                 case 14:    *DstL++ += *SrcL++;
  660.                 case 13:    *DstL++ += *SrcL++;
  661.                 case 12:    *DstL++ += *SrcL++;
  662.                 case 11:    *DstL++ += *SrcL++;
  663.                 case 10:    *DstL++ += *SrcL++;
  664.                 case 9:        *DstL++ += *SrcL++;
  665.                 case 8:        *DstL++ += *SrcL++;
  666.                 case 7:        *DstL++ += *SrcL++;
  667.                 case 6:        *DstL++ += *SrcL++;
  668.                 case 5:        *DstL++ += *SrcL++;
  669.                 case 4:        *DstL++ += *SrcL++;
  670.                 case 3:        *DstL++ += *SrcL++;
  671.                 case 2:        *DstL++ += *SrcL++;
  672.                 case 1:        *DstL++ += *SrcL++;
  673.                 case 0:;
  674.             }
  675.         }
  676.         if(bytes&2){
  677.             *(unsigned short *)DstL += *(unsigned short *)SrcL;
  678.             DstL=(unsigned long *)(1+(unsigned short *)DstL);
  679.             SrcL=(unsigned long *)(1+(unsigned short *)SrcL);
  680.         }
  681.         if(bytes&1){
  682.             *(unsigned char *)DstL += *(unsigned char *)SrcL;
  683.             DstL=(unsigned long *)(1+(unsigned char *)DstL);
  684.             SrcL=(unsigned long *)(1+(unsigned char *)SrcL);
  685.         }
  686.         DstL=(unsigned long *)(dstinc+(unsigned char *)DstL);
  687.         SrcL=(unsigned long *)(srcinc+(unsigned char *)SrcL);
  688.     }
  689.     if(do32)SwapMMUMode((void *)&mmumode);    /* restore */
  690. }
  691.  
  692. static void AddOver8(register UPtr Src,register unsigned long srcinc,
  693.     register UPtr Dst,register unsigned long dstinc,
  694.     register unsigned long bytes,register unsigned long lines,Boolean do32)
  695. {
  696.     register long i;
  697.     signed char mmumode;
  698.  
  699.     mmumode=true32b;
  700.     if(do32)SwapMMUMode((void *)&mmumode);    /* set 32-bit mode */
  701.     for(;lines>0;lines--) {
  702.         i=bytes>>5;
  703.         switch(bytes&31){
  704.             for(;i>=0;i--){
  705.                             *Dst++ += *Src++;
  706.                 case 31:    *Dst++ += *Src++;
  707.                 case 30:    *Dst++ += *Src++;
  708.                 case 29:    *Dst++ += *Src++;
  709.                 case 28:    *Dst++ += *Src++;
  710.                 case 27:    *Dst++ += *Src++;
  711.                 case 26:    *Dst++ += *Src++;
  712.                 case 25:    *Dst++ += *Src++;
  713.                 case 24:    *Dst++ += *Src++;
  714.                 case 23:    *Dst++ += *Src++;
  715.                 case 22:    *Dst++ += *Src++;
  716.                 case 21:    *Dst++ += *Src++;
  717.                 case 20:    *Dst++ += *Src++;
  718.                 case 19:    *Dst++ += *Src++;
  719.                 case 18:    *Dst++ += *Src++;
  720.                 case 17:    *Dst++ += *Src++;
  721.                 case 16:    *Dst++ += *Src++;
  722.                 case 15:    *Dst++ += *Src++;
  723.                 case 14:    *Dst++ += *Src++;
  724.                 case 13:    *Dst++ += *Src++;
  725.                 case 12:    *Dst++ += *Src++;
  726.                 case 11:    *Dst++ += *Src++;
  727.                 case 10:    *Dst++ += *Src++;
  728.                 case 9:        *Dst++ += *Src++;
  729.                 case 8:        *Dst++ += *Src++;
  730.                 case 7:        *Dst++ += *Src++;
  731.                 case 6:        *Dst++ += *Src++;
  732.                 case 5:        *Dst++ += *Src++;
  733.                 case 4:        *Dst++ += *Src++;
  734.                 case 3:        *Dst++ += *Src++;
  735.                 case 2:        *Dst++ += *Src++;
  736.                 case 1:        *Dst++ += *Src++;
  737.                 case 0:;
  738.             }
  739.         }
  740.         Src += srcinc;
  741.         Dst += dstinc;
  742.     }
  743.     if(do32)SwapMMUMode((void *)&mmumode);    /* restore */
  744. }
  745.  
  746. // Multiply two unsigned 8-bit pixels, and divide the product by 128.
  747. static void MulOver8(register UPtr Src,register unsigned long srcinc,
  748.     register UPtr Dst,register unsigned long dstinc,
  749.     register unsigned long bytes,register unsigned long lines,Boolean do32)
  750. {
  751.     register long i;
  752.     signed char mmumode;
  753.  
  754.     mmumode=true32b;
  755.     if(do32)SwapMMUMode((void *)&mmumode);    /* set 32-bit mode */
  756.     for(;lines>0;lines--) {
  757.         i=bytes>>4;
  758.         switch(bytes&15){
  759.             for(;i>=0;i--){
  760.                             *Dst = ((unsigned short)(*Dst)*(*Src++))>>7; Dst++;
  761.                 case 15:    *Dst = ((unsigned short)(*Dst)*(*Src++))>>7; Dst++;
  762.                 case 14:    *Dst = ((unsigned short)(*Dst)*(*Src++))>>7; Dst++;
  763.                 case 13:    *Dst = ((unsigned short)(*Dst)*(*Src++))>>7; Dst++;
  764.                 case 12:    *Dst = ((unsigned short)(*Dst)*(*Src++))>>7; Dst++;
  765.                 case 11:    *Dst = ((unsigned short)(*Dst)*(*Src++))>>7; Dst++;
  766.                 case 10:    *Dst = ((unsigned short)(*Dst)*(*Src++))>>7; Dst++;
  767.                 case 9:        *Dst = ((unsigned short)(*Dst)*(*Src++))>>7; Dst++;
  768.                 case 8:        *Dst = ((unsigned short)(*Dst)*(*Src++))>>7; Dst++;
  769.                 case 7:        *Dst = ((unsigned short)(*Dst)*(*Src++))>>7; Dst++;
  770.                 case 6:        *Dst = ((unsigned short)(*Dst)*(*Src++))>>7; Dst++;
  771.                 case 5:        *Dst = ((unsigned short)(*Dst)*(*Src++))>>7; Dst++;
  772.                 case 4:        *Dst = ((unsigned short)(*Dst)*(*Src++))>>7; Dst++;
  773.                 case 3:        *Dst = ((unsigned short)(*Dst)*(*Src++))>>7; Dst++;
  774.                 case 2:        *Dst = ((unsigned short)(*Dst)*(*Src++))>>7; Dst++;
  775.                 case 1:        *Dst = ((unsigned short)(*Dst)*(*Src++))>>7; Dst++;
  776.                 case 0:;
  777.             }
  778.         }
  779.         Src += srcinc;
  780.         Dst += dstinc;
  781.     }
  782.     if(do32)SwapMMUMode((void *)&mmumode);    /* restore */
  783. }
  784.